/*
 *  dbxcommon.hpp - dbExpress common part for drivers realization
 *
 *    Copyright (c) 2001-2006, Luxena Software Company. All rights reserved.
 *
 *  Purpose:
 *
 */

#ifndef __DBXCOMMON_HPP__
#define __DBXCOMMON_HPP__

#ifndef __cplusplus
#error This header requires a C++ compiler ...
#endif

#include <exception>
#include <new>
#include <memory.h>
#include <stdio.h>
#include <stdarg.h>
#include "cstr.hpp"
#include "dbxpress.hpp"


/////////////////////////////////////////////////////////////////////////////
// CUnknownImpl - SQLUnknown implementation

template <class T>
class CUnknownImpl : public T
{
public:
	CUnknownImpl (): _refCount(1) {}
	virtual ~CUnknownImpl () {}

// SQLUnknown
public:
	COM_METHOD(INT32) QueryInterface (const SQLUnknown::GUID& riid, void **ppvObject);
	COM_METHOD(UINT32) AddRef ();
	COM_METHOD(UINT32) Release ();

private:
	UINT32 _refCount;
};

template <class T>
COM_METHOD_IMP(INT32) CUnknownImpl<T>::QueryInterface (const SQLUnknown::GUID& riid, void **ppvObject)
{
	*ppvObject = static_cast<SQLUnknown *>(this);
	AddRef();
	return 0;
}

template <class T>
COM_METHOD_IMP(UINT32) CUnknownImpl<T>::AddRef ()
{
	return ++_refCount;
}

template <class T>
COM_METHOD_IMP(UINT32) CUnknownImpl<T>::Release ()
{
	UINT32 l = --_refCount;
	if (l == 0)
		delete this;
	return l;
}


/////////////////////////////////////////////////////////////////////////////
// CErrorHandlingImpl - implementation for error handling methods

struct IErrorRegister
{
	virtual void registerError (const char *errorMessage) = 0;
};

template <class T>
class CErrorHandlingImpl : public T
{
public:
	virtual ~CErrorHandlingImpl() {}

	virtual void setErrorMessage (const char* errorMessage) {
		_errorMessage = errorMessage;
		_errorRegister->registerError(errorMessage);
	}

	const char * getErrorMessage() { return _errorMessage; }

	SQL_METHOD getErrorMessage (pBYTE pszError);
	SQL_METHOD getErrorMessageLen (pUINT16 puErrorLen);

protected:
	IErrorRegister *_errorRegister;
	
private:
	_cstr_t _errorMessage;
};

template <class T>
SQL_METHOD_IMP CErrorHandlingImpl<T>::getErrorMessage (pBYTE pszError)
{
	if (_errorMessage == 0)
		return SQL_NULL_DATA;
	memcpy(pszError, _errorMessage, strlen(_errorMessage) + 1);
	return SQL_SUCCESS;
}

template <class T>
SQL_METHOD_IMP CErrorHandlingImpl<T>::getErrorMessageLen (pUINT16 puErrorLen)
{
	if (_errorMessage == 0)
		return SQL_NULL_DATA;
	*puErrorLen = strlen(_errorMessage) + 1;
	return SQL_SUCCESS;
}

#define SAFE_SQL_METHOD {\
	try

#define RETURN_SQL_RESULT \
		return SQL_SUCCESS;\
	} catch (std::bad_alloc&) {\
		setErrorMessage("Memory allocation failure.");\
		return DBXERR_NOMEMORY;\
	} catch (std::exception& e) {\
		setErrorMessage(e.what());\
		return SQL_ERROR;\
	} catch (SQLResult sqlResult) {\
		return sqlResult;\
	} catch (...) {\
		setErrorMessage("Unknown exception caught. File "__FILE__".");\
		return SQL_ERROR;\
	}

#define ENTER_SAFE_CODE \
	try {

#define LEAVE_SAFE_CODE \
	} catch (std::bad_alloc&) {\
		setErrorMessage("Memory allocation failure.");\
	} catch (std::exception& e) {\
		setErrorMessage(e.what());\
	} catch (...) {\
		setErrorMessage("Unknown exception caught. File "__FILE__".");\
	}


/////////////////////////////////////////////////////////////////////////////
// CCallback

class CCallback
{
public:
	CCallback(): _handler(0) {}

	void setHandler (pfCallBack handler) { _handler = handler; }
	pfCallBack getHandler () const { return _handler; }

	void setInfo (INT32 info) { _info = info; }
	INT32 getInfo () const { return _info; }

	void traceMessage (TRACECat traceCat, const char *message, ...) const;

private:
	pfCallBack _handler;
	INT32 _info;
};

#ifdef _MSC_VER
#define vsnprintf _vsnprintf
#define snprintf _snprintf
#endif

inline void CCallback::traceMessage (TRACECat traceCat, const char *message, ...) const
{
	TRACEDesc traceDesc;

	traceDesc.eTraceCat = traceCat;
	traceDesc.iCBInfo = _info;

	va_list argptr;
	va_start(argptr, message);
	traceDesc.uTotalMsgLen = vsnprintf(traceDesc.szTrace, sizeof(traceDesc.szTrace), message, argptr);
	va_end(argptr);

	_handler(cbTRACE, &traceDesc);
}

#define TRACE_MESSAGE(callback) \
	if (callback != 0)\
		callback->traceMessage


/////////////////////////////////////////////////////////////////////////////
// Helper for getOption method realization

inline pINT32 getVerifiedValueDestination (INT16 iLength, pINT32 plValue, INT16 iMaxLength, pINT16 piLength)
{
	if (iMaxLength < iLength)
		throw DBXERR_INVALIDLEN;
	*piLength = iLength;
	return plValue;
}

#endif // __DBXCOMMON_HPP__
